//////////////////////////////////////////////////////////////////////
//
// NO_Constructor.h: interface for the NO_Constructor class.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
#ifndef NO_CONSTRUCTOR_H
#define NO_CONSTRUCTOR_H

//////////////////////////////////////////////////////////////////////////
#include "NO_Includes.h"

//////////////////////////////////////////////////////////////////////////
class NO_Type;

//////////////////////////////////////////////////////////////////////
// cloning
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_NoneCopy
{
protected:
	NO_Value* getCopyImpl (NO_Value&) const;
};

//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_Copy
{
protected:
	NO_Value* getCopyImpl(NO_Value& obj) const
	{
		T* o = noGetDataException<T>(obj);
		return new NO_CopyValue<T>(*o);
	}
};

//////////////////////////////////////////////////////////////////////
// Constructor Interface
//////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_IConstructor
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_IConstructor();
	virtual ~NO_IConstructor();

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const = 0;
	virtual NO_Boolean destruct(NO_Value*) const = 0;

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType	(void)			const = 0;
	virtual NO_TypeList&	getParameter	(NO_TypeList&)	const = 0;

	//////////////////////////////////////////////////////////////////////////
	NO_UInt32 getID(void) const;

protected:
	//////////////////////////////////////////////////////////////////////////
	friend class NO_ConstructorFriend;
	
	//////////////////////////////////////////////////////////////////////////
	NO_UInt32 id;
	NO_IConstructor* next;
};

//////////////////////////////////////////////////////////////////////
// Constructor Template
//////////////////////////////////////////////////////////////////////
template<class T>
class NO_Constructor : public NO_IConstructor 
{
public:
	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType	(void)			const {return NO_TypeID<T>::type();}
	virtual NO_TypeList&	getParameter	(NO_TypeList& p)const {return p;}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(!num){std::exception("Can not allocate array of size 0.");}
		return new NO_ConstructValue<T>(new T, 1);
	} 

	//////////////////////////////////////////////////////////////////////////
	NO_Boolean destruct(NO_Value* v) const
	{
		NO_ConstructValue<T>* cv = dynamic_cast<NO_ConstructValue<T>*>(v);
		if(!cv){std::exception("destruction failed.");}
		delete cv->object;
		delete cv;
		return 1;
	}
};

//////////////////////////////////////////////////////////////////////
// Constructor Template P1
//////////////////////////////////////////////////////////////////////
template<class T, class P1>
class NO_ConstructorP1 : public NO_Constructor<T>
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_ConstructorP1(){}

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType	(void)			const {return NO_TypeID<T>::type();}
	virtual NO_TypeList&	getParameter	(NO_TypeList&)	const {return NO_TypeList()<<NO_TypeID<P1>::type();}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(parameter.size()!=1)	{throw std::exception("Parameter is NULL.");}
		if(num>1)				{throw std::exception("Range construction only with standard constructor allowed.");}

		P1* p1 = noGetData<P1>(parameter[0]);
		return new NO_ConstructValue<T>(new T(*p1),1);
	}
};

//////////////////////////////////////////////////////////////////////
// Constructor Template P2
//////////////////////////////////////////////////////////////////////
template<class T, class P1, class P2>
class NO_ConstructorP2 : public NO_Constructor<T>
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_ConstructorP2(){}

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType(void)	const {return NO_TypeID<T>::type();}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_TypeList& getParameter(NO_TypeList&  p) const
	{
		return p<<NO_TypeID<P1>::type()
				<<NO_TypeID<P2>::type();
	}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(parameter.size()!=2)	{throw std::exception("Invalid number of parameters.");}
		if(num>1)				{throw std::exception("Range construction only with standard constructor allowed.");}

		P1* p1 = noGetData<P1>(parameter[0]);
		P2* p2 = noGetData<P2>(parameter[1]);
		return new NO_ConstructValue<T>(new T(*p1,*p2),1);
	}
};

//////////////////////////////////////////////////////////////////////
// Constructor Template P3
//////////////////////////////////////////////////////////////////////
template<class T, class P1, class P2, class P3>
class NO_ConstructorP3 : public NO_Constructor<T> 
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_ConstructorP3(){}

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType(void)	const {return NO_TypeID<T>::type();}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_TypeList& getParameter(NO_TypeList& p) const
	{
		return p<<NO_TypeID<P1>::type()
				<<NO_TypeID<P2>::type();
				<<NO_TypeID<P3>::type();
	}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(parameter.size()!=3)	{throw std::exception("Invalid number of parameters.");}
		if(num>1)				{throw std::exception("Range construction only with standard constructor allowed.");}

		P1* p1 = noGetData<P1>(parameter[0]);
		P2* p2 = noGetData<P2>(parameter[1]);
		P3* p3 = noGetData<P3>(parameter[2]);
		return new NO_ConstructValue<T>(new T(*p1,*p2,*p3),1);
	}	
};

//////////////////////////////////////////////////////////////////////
// Constructor Template P4
//////////////////////////////////////////////////////////////////////
template<class T, class P1, class P2, class P3, class P4>
class NO_ConstructorP4 : public NO_Constructor<T> 
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_ConstructorP4(){}

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType(void)	const {return NO_TypeID<T>::type();}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_TypeList& getParameter(NO_TypeList& p) const
	{
		return  p<<NO_TypeID<P1>::type()
				 <<NO_TypeID<P2>::type();
				 <<NO_TypeID<P3>::type();
				 <<NO_TypeID<P4>::type();
	}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(parameter.size()!=4)	{throw std::exception("Invalid number of parameters.");}
		if(num>1)				{throw std::exception("Range construction only with standard constructor allowed.");}

		P1* p1 = noGetData<P1>(parameter[0]);
		P2* p2 = noGetData<P2>(parameter[1]);
		P3* p3 = noGetData<P3>(parameter[2]);
		P4* p4 = noGetData<P4>(parameter[3]);
		return new NO_ConstructValue<T>(new T(*p1,*p2,*p3,*p4),1);
	}
};

//////////////////////////////////////////////////////////////////////
// Constructor Template P5
//////////////////////////////////////////////////////////////////////
template<class T, class P1, class P2, class P3, class P4, class P5>
class NO_ConstructorP5 : public NO_Constructor<T> 
{
public:
	//////////////////////////////////////////////////////////////////////////
	NO_ConstructorP5(){}

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType(void)	const {return NO_TypeID<T>::type();}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_TypeList& getParameter(NO_TypeList& p) const
	{
		return  p<<NO_TypeID<P1>::type()
				 <<NO_TypeID<P2>::type();
				 <<NO_TypeID<P3>::type();
				 <<NO_TypeID<P4>::type();
				 <<NO_TypeID<P5>::type();
	}

	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Value* construct(NO_UInt32 num, NO_ObjectList& parameter) const 
	{
		if(parameter.size()!=5)	{throw std::exception("Invalid number of parameters.");}
		if(num>1)				{throw std::exception("Range construction only with standard constructor allowed.");}

		P1* p1 = noGetData<P1>(parameter[0]);
		P2* p2 = noGetData<P2>(parameter[1]);
		P3* p3 = noGetData<P3>(parameter[2]);
		P4* p4 = noGetData<P4>(parameter[3]);
		P5* p5 = noGetData<P5>(parameter[4]);
		return new NO_ConstructValue<T>(new T(*p1,*p2,*p3,*p4,*p5),1);
	}	
};

//////////////////////////////////////////////////////////////////////////
// class NO_MemberFriend definition
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_ConstructorFriend  
{
protected:
	//////////////////////////////////////////////////////////////////////////
	NO_IConstructor*	getNext	(const NO_IConstructor*)				const;
	void				setNext	(NO_IConstructor*, NO_IConstructor*)	const;
	void				setID	(NO_IConstructor*, NO_UInt32)			const;
};

//////////////////////////////////////////////////////////////////////////
// class NO_ConstructorList definition
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_ConstructorList : public NO_ConstructorFriend
{
public:
	//////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_ConstructorList(void);
	~NO_ConstructorList(void);
	
	//////////////////////////////////////////////////////////////////////////
	// modify
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Boolean addConstructor(NO_IConstructor* obj);
	
	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* findConstructorImpl(const NO_TypeList&)	const;
	const NO_IConstructor* findConstructorImpl(NO_UInt32 ID)		const;

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* beginConstructorImpl	(void) const;
	const NO_IConstructor* endConstructorImpl	(void) const;
	const NO_IConstructor* nextConstructorImpl	(const NO_IConstructor*) const;

private:
	//////////////////////////////////////////////////////////////////////
	NO_IConstructor* first;
	NO_IConstructor* last;
};

//////////////////////////////////////////////////////////////////////////
// class NO_ConstructorList definition
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_SingleConstructor
{
public:
	//////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_SingleConstructor(void);
	~NO_SingleConstructor(void);
	
	//////////////////////////////////////////////////////////////////////////
	// modify
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_Boolean addConstructor(NO_IConstructor* obj);
	
	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* findConstructorImpl(const NO_TypeList&)	const;
	const NO_IConstructor* findConstructorImpl(NO_UInt32 ID)		const;

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* beginConstructorImpl	(void) const;
	const NO_IConstructor* endConstructorImpl	(void) const;
	const NO_IConstructor* nextConstructorImpl	(const NO_IConstructor*) const;

private:
	//////////////////////////////////////////////////////////////////////////
	NO_IConstructor* constructor;
};

//////////////////////////////////////////////////////////////////////////
// class NO_ConstructorList definition
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_NoneConstructors 
{
public:
	//////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_NoneConstructors(void);
	~NO_NoneConstructors(void);
	
	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* findConstructorImpl(const NO_TypeList&)	const;
	const NO_IConstructor* findConstructorImpl(NO_UInt32 ID)		const;

	//////////////////////////////////////////////////////////////////////////
	const NO_IConstructor* beginConstructorImpl	(void) const;
	const NO_IConstructor* endConstructorImpl	(void) const;
	const NO_IConstructor* nextConstructorImpl	(const NO_IConstructor*&) const;
};

#endif 
